package alipay

import (
	"context"
	"encoding/json"
	"errors"
	"log/slog"
	"net/url"
	"strconv"
	"time"

	"gitee.com/gxcc/go-utils/utils"
	"github.com/smartwalle/alipay/v3"
)

type AliPaySvc struct {
	AliPayAppId               string `json:"aliPayAppId"`
	AliPayPartnerId           string `json:"aliPayPartnerId"`
	AliPayAppRsa2PrivateKey   string `json:"aliPayAppRsa2PrivateKey"`
	AliPayAppRsa2PublicKey    string `json:"aliPayAppRsa2PublicKey"`
	AliPayRsa2AlipayPublicKey string `json:"aliPayRsa2AlipayPublicKey"`
	AliPayAESEncryptKey       string `json:"aliPayAESEncryptKey"`
	AliPayNotifyUrl           string `json:"aliPayNotifyUrl"`
	IsProduction              bool   `json:"isProduction"`

	client *alipay.Client
}

func (svc *AliPaySvc) GetAlipayClient() (*alipay.Client, error) {
	if svc.client == nil {
		client, err := alipay.New(svc.AliPayAppId, svc.AliPayAppRsa2PrivateKey, svc.IsProduction)
		if err != nil {
			slog.Error(err.Error())
			return nil, err
		}
		if len(svc.AliPayRsa2AlipayPublicKey) > 0 {
			err = client.LoadAliPayPublicKey(svc.AliPayRsa2AlipayPublicKey)
			if err != nil {
				return nil, err
			}
		}
		if len(svc.AliPayAESEncryptKey) > 0 {
			err = client.SetEncryptKey(svc.AliPayAESEncryptKey)
			if err != nil {
				return nil, err
			}
		}
		svc.client = client
	}
	return svc.client, nil
}

// PayByApp app调用支付下单
// outTradeNo: 业务系统订单交易号
// totalAmount: 金额
// subject: 商品/订单标题
// body: 描述内容
// 返回值：支付宝交易ID
func (svc *AliPaySvc) PayByApp(outTradeNo string, totalAmount int64, subject string, body string, expireTime time.Time) (string, error) {
	var appPay = alipay.TradeAppPay{
		Trade: alipay.Trade{
			NotifyURL:          svc.AliPayNotifyUrl,
			ReturnURL:          "",
			Subject:            subject,
			OutTradeNo:         outTradeNo,
			TotalAmount:        strconv.FormatFloat(float64(totalAmount)/100, 'f', 2, 64),
			ProductCode:        "",
			Body:               body,
			BusinessParams:     nil,
			DisablePayChannels: "",
			EnablePayChannels:  "",
			PassbackParams:     "",
			TimeExpire:         expireTime.Format(utils.TimeFormatDateTime),
		},
	}

	client, _ := svc.GetAlipayClient()
	return client.TradeAppPay(appPay)
}

// PayByWap 手机网页调用支付下单
func (svc *AliPaySvc) PayByWap(outTradeNo string, totalAmount int64, subject string, body string, quitURl string, expireTime time.Time) (*url.URL, error) {
	var wapPay = alipay.TradeWapPay{
		Trade: alipay.Trade{
			NotifyURL:          svc.AliPayNotifyUrl,
			ReturnURL:          "",
			Subject:            subject,
			OutTradeNo:         outTradeNo,
			TotalAmount:        strconv.FormatFloat(float64(totalAmount)/100, 'f', 2, 64),
			ProductCode:        "",
			Body:               body,
			BusinessParams:     nil,
			DisablePayChannels: "",
			EnablePayChannels:  "",
			PassbackParams:     "",
		},
		QuitURL:    quitURl,
		AuthToken:  "",
		TimeExpire: expireTime.Format(utils.TimeFormatDateTime),
	}

	client, _ := svc.GetAlipayClient()
	return client.TradeWapPay(wapPay)
}

// PayByWeb 电脑网页调用支付下单
func (svc *AliPaySvc) PayByWeb(outTradeNo string, totalAmount int64, subject string, qrPayMode string, qrCodeWidth int, expireTime time.Time) (*url.URL, error) {
	var pagePay = alipay.TradePagePay{
		Trade: alipay.Trade{
			NotifyURL:   svc.AliPayNotifyUrl,
			ReturnURL:   "",
			Subject:     subject,
			OutTradeNo:  outTradeNo,
			TotalAmount: strconv.FormatFloat(float64(totalAmount)/100, 'f', 2, 64),
			ProductCode: "FAST_INSTANT_TRADE_PAY",
			TimeExpire:  expireTime.Format(utils.TimeFormatDateTime),
		},
		AuthToken:   "",
		QRPayMode:   qrPayMode,
		QRCodeWidth: strconv.Itoa(qrCodeWidth),
	}

	client, _ := svc.GetAlipayClient()
	return client.TradePagePay(pagePay)
}

// Refund 退款
func (svc *AliPaySvc) Refund(outTradeNo string, refundAmount int64, refundReason string, outRequestNo string) (*alipay.TradeRefundRsp, error) {
	var tradeRefund = alipay.TradeRefund{
		OutTradeNo:   outTradeNo,
		RefundAmount: strconv.FormatFloat(float64(refundAmount)/100, 'f', 2, 64),
		RefundReason: refundReason,
		OutRequestNo: outRequestNo,
	}

	client, _ := svc.GetAlipayClient()
	resp, err := client.TradeRefund(context.Background(), tradeRefund)
	if err != nil {
		slog.Error(err.Error())
		return nil, err
	}
	if !resp.IsSuccess() {
		jsonData, _ := json.Marshal(resp)
		slog.Warn(string(jsonData))
		return nil, errors.New(resp.Error.Error())
	}

	return resp, nil
}

// Query 查询订单
func (svc *AliPaySvc) Query(outTradeNo string) (*alipay.TradeQueryRsp, error) {
	var wapPay = alipay.TradeQuery{
		AppAuthToken: "",
		OutTradeNo:   outTradeNo,
		TradeNo:      "",
	}

	client, _ := svc.GetAlipayClient()
	resp, err := client.TradeQuery(context.Background(), wapPay)
	if err != nil {
		slog.Error(err.Error())
		return nil, err
	}
	if !resp.IsSuccess() {
		jsonData, _ := json.Marshal(resp)
		slog.Warn(string(jsonData))
		return nil, errors.New(resp.Error.Error())
	}

	return resp, nil
}
